home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1997 September / Macworld (1997-09).dmg / Serious Software / Cherwell Scientific Demos / pro Fit / pro Fit 5.0 demo (fpu).sea / pro Fit 5.0 demo (fpu) / External Modules / External modules sources / C / Utility files / ModuleUtilities.c next >
Text File  |  1996-06-30  |  24KB  |  861 lines

  1. /*  version history:
  2.     28.6.96:    Added routines MySetFrame, MySetTimer,
  3.                 MyAppendDITL, MyShortenDITL, MyInvalidateItem
  4. */
  5.  
  6.  
  7. #ifndef __PROFIT_INTERFACE__
  8. #include "proFit_interface.h"
  9. #endif
  10. #ifndef __MODULE_UTILITIES__
  11. #include "ModuleUtilities.h"
  12. #endif
  13. #ifndef __TRAPS__
  14. #include <Traps.h>
  15. #endif
  16. #ifndef __STRING_SUPPORT__
  17. #include "StringSupport.h"
  18. #endif
  19.  
  20.  
  21. // NOTE: this unit uses static variables!
  22.  
  23.  
  24. #define maxNrItemsInWindowPopup 50  /* max number of items in a window popup item */
  25.  
  26. // the purpose of the following pragmas is to define the symbol USE_SANE
  27. // This symbol is 1 if math.h is to be used, 0 if fp.h
  28. // Depending on the compiler you have, you may have to change it
  29.  
  30. #if defined THINK_C
  31.     #define USE_SANE 1
  32. #else
  33.     #define USE_SANE 0
  34. #endif
  35.  
  36. #if USE_SANE 
  37.     #include <math.h>
  38. #else
  39.     #include <fp.h>
  40. #endif
  41.  
  42.  
  43.  
  44. typedef struct WindowEntry            // an entry in our private window list
  45. {
  46.     WindowPtr            window;
  47.     WindowHandler        windowHandler;
  48.     void*                data;            // data to be passed to the event handler
  49.     Rect                growRect;        // if canGrow==true: contains min and max size of window
  50.  
  51.     struct WindowEntry*    next;            // linked list
  52.  
  53. }WindowEntry;
  54.  
  55.  
  56. static WindowEntry*    firstWindowEntry=nil;            // our private list of windows
  57.  
  58.  
  59.  
  60. typedef long WindowArray[maxNrItemsInWindowPopup];    // used for holding window references in window popups
  61.  
  62. void GetGlobalWindowRect(WindowPtr window, Rect* const r)
  63.     // returns the window's rect in global coordinates
  64. {    GrafPtr    oldPort;
  65.     GetPort(&oldPort);
  66.     SetPort(window);
  67.     *r = window->portRect;
  68.     LocalToGlobal((Point*)&r->top);
  69.     LocalToGlobal((Point*)&r->bottom);
  70.     SetPort(oldPort);
  71. }
  72.  
  73. static void CenterWindow(WindowPtr window)
  74.     // centers window on main screen
  75. {
  76.     Rect            mainRect = (**GetMainDevice()).gdRect;    // rectangle of main device
  77.     Rect            r;
  78.     short            dh, dv;
  79.  
  80.     r = window->portRect;
  81.     dh = mainRect.left + (mainRect.right - mainRect.left - (r.right - r.left)) / 2;
  82.     dv = mainRect.top + (mainRect.bottom - mainRect.top - (r.bottom - r.top)) / 3;
  83.     MoveWindow(window, dh, dv+14, false);
  84. }
  85.  
  86.  
  87. void SetGlobalWindowRect(WindowPtr window, Rect* const r)
  88.     // moves the window to the given global coordinates
  89.     // Centers the window if r = {0,0,0,0} or if window is at a bad position
  90. {
  91.     if (r->left!=0 && r->right!=0)
  92.     {
  93.         Rect    title = *r;                // rect enclosing the window's title
  94.  
  95.         title.bottom = title.top;
  96.         title.top -= 16;
  97.         InsetRect(&title, 5, 3);
  98.         if (RectInRgn(&title, GetGrayRgn()))    // if window still draggable
  99.         {    SizeWindow(window, r->right-r->left, r->bottom-r->top, true);
  100.             MoveWindow(window, r->left, r->top, false);
  101.         }
  102.         else CenterWindow(window);
  103.     }
  104.     else
  105.         CenterWindow(window);
  106. }
  107.  
  108.  
  109. void RegisterWindow(WindowPtr window, WindowHandler handler, void* param)
  110.     // register a private window of this module
  111.     // window: the window ptr to it
  112.     // handler: called for handling window related events, must at least implement update events
  113.     // param: parameter passed each time handler is called
  114. {
  115.     WindowEntry**    p;
  116.     WindowEntry*    newEntry = (WindowEntry*)NewPtrClear(sizeof(WindowEntry));
  117.  
  118.     if (newEntry==nil) return;
  119.     newEntry->window = window;
  120.     newEntry->windowHandler = handler;
  121.     newEntry->data = param;
  122.     p = &firstWindowEntry;
  123.  
  124.     while (*p != nil) p = &(**p).next;                // find end of list
  125.     *p = newEntry;
  126.  
  127. }
  128.  
  129.  
  130. void UnregisterWindow(WindowPtr window)
  131.     // unregister a private window previously registered by RegisterWindow
  132. {
  133.     WindowEntry**     p = &firstWindowEntry;
  134.  
  135.     while(*p != nil)                                // go through window entries
  136.     {    if ((**p).window == window)                    // if found
  137.         {
  138.             WindowEntry*     next = (**p).next;
  139.         
  140.             DisposePtr((Ptr)*p);                    // remove it
  141.             *p = next;
  142.             return;
  143.         }
  144.         p = &(**p).next;
  145.     }//while
  146. }
  147.  
  148. static WindowEntry* FindWindowEntry(WindowPtr window)
  149.     // given a windowPtr, returns its windowEntry or nil if no such entry
  150. {
  151.     WindowEntry*     p = firstWindowEntry;
  152.     while(p != nil)                                    // go through window entries
  153.     {    if (p->window == window)                    // if found
  154.             return p;
  155.         p = p->next;
  156.     }//while
  157.     return nil;                                        // if not found
  158. }
  159.  
  160.  
  161.  
  162. void EventLoop(void)
  163.     // Gets events and handles them until a window handler returns false
  164. {
  165.     EventRecord        event;
  166.     Boolean            done = false;
  167.     WindowEntry*    entry;
  168.  
  169.     while (!done)
  170.     {
  171.         WaitNextEvent(everyEvent-highLevelEventMask, &event, 1, nil);    
  172.             // do not get high level events because DoEvent will not
  173.             // handle them when not in main loop
  174.  
  175.         if(event.what == activateEvt || event.what == updateEvt)
  176.         {    entry = FindWindowEntry((WindowPtr)event.message);
  177.             if (entry != nil)                                    // if we have an event handler
  178.                 (*entry->windowHandler)('evnt', &event, entry->data);    // then call it, ignore its return value
  179.             else
  180.                 HandleEvent(&event);                            // else pro Fit should be able to handle it
  181.         }
  182.         else if (event.what == mouseDown)                        // test if user is dragging dialog
  183.         {    short         partCode;
  184.             WindowPtr    clickedWindow;
  185.  
  186.             partCode = FindWindow(event.where, &clickedWindow);
  187.             entry = FindWindowEntry(clickedWindow);
  188.             switch(partCode)
  189.             {
  190.             case inDrag:
  191.                         if (clickedWindow==FrontWindow())
  192.                         {
  193.                             Rect    dragRect = (**GetGrayRgn()).rgnBBox;
  194.                             DragWindow(clickedWindow, event.where, &dragRect);
  195.                         }
  196.                         break;
  197.             case inSysWindow:
  198.                         SystemClick(&event, clickedWindow);
  199.                         break;
  200.             case inMenuBar:                                    // make the help and application menu work
  201.                     {    long item =    MenuSelect(event.where);
  202.                         entry = FindWindowEntry(FrontWindow());
  203.                         if (entry)
  204.                             done = (*entry->windowHandler)('menu', &item, entry->data);
  205.                         break;
  206.                     }
  207.             case inGrow:
  208.                     {    Rect growRect;
  209.                         if (entry && (*entry->windowHandler)('grw1', &growRect, entry->data))
  210.                         {
  211.                             Rect     r = (**GetGrayRgn()).rgnBBox;
  212.                             long    wSize;
  213.                             short    maxWidth = r.right - r.left;
  214.                             short    maxHeight = r.bottom - r.top - 24;
  215.                             if (growRect.right > maxWidth) growRect.right = maxWidth;
  216.                             if (growRect.bottom > maxHeight) growRect.bottom = maxHeight;
  217.  
  218.                             wSize = GrowWindow(clickedWindow, event.where, &growRect);
  219.                             SizeWindow(clickedWindow, wSize & 0x00FFFF, ((unsigned long) (wSize)) >> 16, false);
  220.                             (*entry->windowHandler)('grw2', nil, entry->data);
  221.                         }
  222.                         break;
  223.                     }
  224.             case inContent:
  225.                         if (entry && clickedWindow==FrontWindow())
  226.                             done = (*entry->windowHandler)('evnt', &event, entry->data);    // then call it, ignore its return value
  227.             }
  228.         }
  229.         else                                                        // all other events
  230.         {    WindowEntry* entry = FindWindowEntry(FrontWindow());
  231.             if (entry != nil)                                        // if we have an event handler
  232.                     done = (*entry->windowHandler)('evnt', &event, entry->data);    // then call it, ignore its return value
  233.         }
  234.         InitCursor();
  235.     }//while
  236. }//EventLoop
  237.  
  238. #pragma mark -
  239.  
  240.  
  241. static short NumToolboxTraps(void)
  242. {    if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  243.         return 0x200;
  244.     else return 0x400;
  245. }
  246.  
  247. static Boolean TrapAvailable(short theTrap)
  248. {    TrapType    tType;
  249.  
  250.     tType = ((theTrap & 0x0800) != 0) ? ToolTrap: OSTrap;
  251.     if (tType == ToolTrap)
  252.     {    theTrap = theTrap & 0x07FF;
  253.         if (theTrap >= NumToolboxTraps())
  254.             theTrap = _Unimplemented;
  255.     }
  256.     return (NGetTrapAddress(theTrap, tType) != NGetTrapAddress(_Unimplemented, ToolTrap));
  257. }
  258.  
  259.  
  260.  
  261. #pragma mark -
  262.  
  263. double RoundDouble(double x)
  264.     // rounds x to next integer
  265. {
  266. #ifdef __FP__
  267.     return rint(x);
  268. #else                            // rint may not be around, especially for fpu-version
  269.     return floor(x+0.5);
  270. #endif
  271. }
  272.  
  273.  
  274. Rect MyGetItemRect(DialogData* dlg, short item)
  275.     // returns enclosing rect of an item
  276. {
  277.     Rect    r;
  278.     Handle    dummyHandle;
  279.     short    dummyInt;
  280.     
  281.     GetDialogItem(dlg->dialog, item, &dummyInt, &dummyHandle, &r);
  282.     return r;
  283. }
  284.  
  285. void MyInvalidateItem(DialogData* dlg, short item)
  286. {
  287.     Rect    r = MyGetItemRect(dlg, item);
  288.     GrafPtr    oldPort;
  289.     GetPort(&oldPort);
  290.     SetPort(dlg->dialog);
  291.     InvalRect(&r);
  292.     SetPort(oldPort);
  293. }
  294.     
  295. ControlHandle MyGetItemHandle(DialogData* dlg, short item)
  296.     // returns the control handle of an item
  297. {
  298.     Rect    r;
  299.     Handle    retval;
  300.     short    dummyInt;
  301.     
  302.     GetDialogItem(dlg->dialog, item, &dummyInt, &retval, &r);
  303.     return (ControlHandle)retval;
  304. }
  305.  
  306. static short MyGetItemKind(DialogData* dlg, short item)
  307.     // returns the type of an item
  308. {    Handle    dummyHandle;
  309.     Rect    dummyRect;
  310.     short    kind;
  311.  
  312.     GetDItem(dlg->dialog, item, &kind, &dummyHandle, &dummyRect);
  313.     return kind;
  314. }
  315.  
  316. void MyHiliteItem(DialogData* dlg, short item, short value)
  317.     // hilites an item (value == 255 for disabling)
  318. {
  319.     short kind = MyGetItemKind(dlg, item) & 0x7F;
  320.     if (kind >= ctrlItem+btnCtrl && kind <= ctrlItem+resCtrl)
  321.         HiliteControl(MyGetItemHandle(dlg, item), value);
  322. }    
  323.  
  324. void MyShowItem(DialogData* dlg, short item)
  325.     // makes the given item visible
  326. {
  327.     ShowDialogItem(dlg->dialog, item);
  328. }
  329.  
  330. void MyHideItem(DialogData* dlg, short item)
  331.     // makes the given item invisible
  332. {
  333.     HideDialogItem(dlg->dialog, item);
  334. }
  335.  
  336. void MySetItemValue(DialogData* dlg, short item, short value)
  337.     // sets the value of a control an item
  338. {
  339.     short kind = MyGetItemKind(dlg, item) & 0x7F;
  340.     if (kind >= ctrlItem+btnCtrl && kind <= ctrlItem+resCtrl)
  341.         SetControlValue(MyGetItemHandle(dlg, item), value);
  342. }
  343.  
  344. short MyGetItemValue(DialogData* dlg, short item)
  345.     // gets the value of an item
  346. {
  347.     short kind = MyGetItemKind(dlg, item) & 0x7F;
  348.     if (kind >= ctrlItem+btnCtrl && kind <= ctrlItem+resCtrl)
  349.         return GetControlValue(MyGetItemHandle(dlg, item));
  350.     else
  351.         return 0;
  352. }
  353.  
  354. void MyGetItemText(DialogData* dlg, short item, Str255 dest)
  355.     // returns the text in an item
  356. {
  357.     short kind = MyGetItemKind(dlg, item) & 0x7F;
  358.     if (kind == statText || kind == editText)                // if a text item
  359.         GetIText((Handle)MyGetItemHandle(dlg, item), dest);
  360.     else if (kind >= ctrlItem && kind <= ctrlItem+resCtrl)    // if a control
  361.         GetCTitle(MyGetItemHandle(dlg, item), dest);
  362. }
  363.  
  364. void MySetItemText(DialogData* dlg, short item, const Str255 s)
  365.     // sets the text of an item
  366. {
  367.     short kind = MyGetItemKind(dlg, item) & 0x7F;
  368.  
  369.     if (kind == statText || kind == editText)                // if a text item
  370.         SetIText((Handle)MyGetItemHandle(dlg, item), s);
  371.     else if (kind >= ctrlItem && kind <= ctrlItem+resCtrl)    // if a control
  372.         SetCTitle(MyGetItemHandle(dlg, item), s);
  373. }
  374.  
  375. void MySelectItemText(DialogData* dlg, short id, short start, short end)
  376.     // selects a text edit item
  377. {
  378.     SelIText(dlg->dialog, id, start, end);
  379. }
  380.  
  381. void MySetExtendedItem(DialogData* dlg, short id, double val)
  382.     // sets a text item to a floating point number
  383. {    Str255    s;
  384.  
  385.     NumberToStr255(val, s, 1, 7);
  386.     MySetItemText(dlg, id, s);
  387. } // MySetExtendedItem
  388.  
  389. Boolean MyGetExtendedItem(DialogData* dlg, short id, double* const val)
  390.     // retrieves a floating point number from a text item
  391.     // if conversion fails: val is unchanged, the text is selected, and false is returned
  392. {
  393.     Str255    s;
  394.     double    d;
  395.  
  396.     MyGetItemText(dlg, id, s);
  397.  
  398.     if (Str255ToNumber(s, &d) > 1)
  399.     {
  400.         MySelectItemText(dlg, id, 0, 0x7FFF);
  401.         SysBeep(30);
  402.         return false;
  403.     }
  404.     *val = d;
  405.     return true;
  406. }
  407.  
  408. void MySetLongItem(DialogData* dlg, short id, long val)
  409.     // sets a text item to a longint number
  410. {
  411.     Str255    s;
  412.     NumToString(val, s);
  413.     MySetItemText(dlg, id, s);
  414. } // MySetLongItem
  415.  
  416. Boolean MyGetLongItem(DialogData* dlg, short id, long* const val)
  417.     // retrieves a longint number from a text item
  418.     // if conversion fails: val is unchanged, the text is selected, and false is returned
  419. {
  420.     double    d;
  421.     if (MyGetExtendedItem(dlg, id, &d) == false) return false;
  422.     if (d< (double)(-0x7FFFFFFF) || d > (double)0x7FFFFFFF)
  423.     {    MySelectItemText(dlg, id, 0, 0x7FFF);
  424.         SysBeep(30);
  425.         return false;
  426.     }
  427.     *val = RoundDouble(d);
  428.     return true;
  429. }
  430.  
  431. void MySetTimer(DialogData* dlg, long ticks)
  432. {
  433.     dlg->timer = ticks;
  434. }
  435.  
  436. void MySetFrame(DialogData* dlg, Rect* const r, short index)
  437.     // Sets a frame that must be drawn whenever the dialog box is updated
  438.     // Set r to nil if you want to clear a frame
  439.     // There are up to 4 frames. Each is identified by its index (0..3)
  440. {
  441.     if (r==nil) SetRect(&dlg->frames[index],0,0,0,0);
  442.     else dlg->frames[index] = *r;
  443. }
  444.  
  445. void FlashControl(ControlHandle control)
  446.     // hilites the control for a moment
  447. {
  448.     long    endTime;
  449.  
  450.     HiliteControl(control, 1);
  451.     Delay(8, &endTime);
  452.     HiliteControl(control, 0);
  453. }
  454.  
  455. static void FlashButton (DialogData* dlg, short item)        // make the button with item nr. itNr flash
  456. {    short    kind;
  457.     Rect    uselessBox;
  458.     Handle    itemH;
  459.  
  460.     GetDItem(dlg->dialog, item, &kind, &itemH, &uselessBox);        // get control handle
  461.     if (kind == ctrlItem || kind == statText - 1)                // if it is really a control
  462.         FlashControl((ControlHandle)(itemH));
  463. }
  464.  
  465.  
  466. #pragma mark -
  467.  
  468.  
  469. void AddItemToMenu(MenuHandle menu, Str255 name)
  470.     // adds an item with the given name to the given menu
  471.     // makes sure that the name contains no illegal characters that would mess up the menu
  472. {
  473.     if (Length(name)>0 && name[1]=='-') name[1] = 208;    // replace '-' by option-dash because '-' makes separation
  474.     AppendMenu(menu, "\p ");                            // don't use AppendMenu for adding the name because it recognizes a lot of meta chars
  475.     SetMenuItemText(menu, CountMItems(menu), name);
  476. }
  477.  
  478.  
  479. void MakeWindowPopup(DialogData* dlg, short item, long windowType)
  480.     // adds a list of windows to the given popup item
  481.     // windowType can be drawingType, dataType or textType and defines
  482.     // the window type that should be added to the menu
  483. {
  484.     MenuHandle        menu;
  485.     ControlHandle    control = (ControlHandle)MyGetItemHandle(dlg,item);
  486.     WindowArray**    array;
  487.     long            count;
  488.     long            windowRef;
  489.  
  490.     if (control==nil) return;                                        // should never happen
  491.     menu = (**(PopupPrivateData**)(**control).contrlData).mHandle;    // a handle to the menu
  492.     if (menu==nil) return;                                            // should never happen
  493.  
  494.     array = (WindowArray**)NewHandleClear(sizeof(WindowArray));
  495.     if (array == nil) return;
  496.  
  497.     dlg->items[item].type = windowPopupItem;
  498.     dlg->items[item].data = array;
  499.  
  500.     while(CountMItems(menu)) DeleteMenuItem(menu, 1);    // delete all present items in the menu
  501.  
  502.     count = 0;
  503.     windowRef = FrontmostWindow(windowType);                // now find all windows
  504.     while (windowRef && count < maxNrItemsInWindowPopup)
  505.     {    if (GetWindowType(windowRef) == windowType)
  506.         {    Str255    s;
  507.             (**array)[count++] = windowRef;
  508.             GetWindowTitle(windowRef, s);
  509.             AddItemToMenu(menu, s);
  510.         }
  511.         windowRef = NextWindow(windowRef);
  512.     }
  513.     SetControlMaximum(control, count);
  514.     SetControlValue(control, 1);
  515. }
  516.  
  517.  
  518. static void UpdateColumnPopup(DialogData* dlg, short item)
  519.     // updates a column popup to the names of its window
  520. {
  521.     MenuHandle        menu;
  522.     ControlHandle    control = (ControlHandle)MyGetItemHandle(dlg,item);
  523.     long            windowRefID;
  524.     short            windowPopupItem    = dlg->items[item].n2;
  525.     short            what = dlg->items[item].n1;                        // 0 if all columns, 1 if only data columns, 2 if only text columns
  526.     long            i;
  527.     long            oldCurrentDataWindow = GetCurrentWindow(dataType);
  528.     long            nrCols;
  529.     GrafPtr            oldPort;
  530.  
  531.     if (control==nil) return;                                        // should never happen
  532.     menu = (**(PopupPrivateData**)(**control).contrlData).mHandle;    // a handle to the menu
  533.     if (menu==nil) return;                                            // should never happen
  534.  
  535.     if (windowPopupItem != 0) GetItemGeneral(dlg, windowPopupItem, &windowRefID);
  536.     else windowRefID = FrontmostWindow(dataType);
  537.  
  538.     if (dlg->items[item].n3 == windowRefID) return;                    // if the window did not change
  539.     dlg->items[item].n3 = windowRefID;
  540.  
  541.     while(CountMItems(menu)) DeleteMenuItem(menu, 1);                // delete all present items in the menu
  542.  
  543.     if (windowRefID)
  544.     {    SetCurrentWindow(windowRefID);
  545.         nrCols = NrCols();
  546.         if (nrCols > 128) nrCols = 128;                                // limit the size of the popup
  547.         for (i=1; i<=nrCols; i++)
  548.         {
  549.             long    colType = GetColType(i);
  550.     
  551.             if ( what == 0 ||
  552.                 (what == 1 && (colType == floatColumn || colType == doubleColumn)) ||
  553.                 (what == 2 && colType == textColumn))
  554.                     {
  555.                         Str255    s;
  556.                         GetColName(s, i);
  557.                         AddItemToMenu(menu, s);
  558.                     }
  559.         }
  560.         SetControlMaximum(control, CountMItems(menu));
  561.         SetCurrentWindow(oldCurrentDataWindow);                            // restore previous data window
  562.     }
  563.     GetPort(&oldPort);
  564.     SetPort(dlg->dialog);
  565.     Draw1Control(control);
  566.     SetPort(oldPort);    
  567. }//UpdateColumnPopup
  568.  
  569. void MakeColumnPopup(DialogData* dlg, short item, short windowPopup, short what)
  570.     // adds a list of column names to a popup item
  571.     //    windowPopup:    the item id of a window popup that this item belongs to, 0 if none
  572.     //    what:            0 if all columns, 1 if only data columns, 2 if only text columns
  573. {
  574.     dlg->items[item].type = columnPopupItem;
  575.     dlg->items[item].n1 = what;
  576.     dlg->items[item].n2 = windowPopup;
  577.     UpdateColumnPopup(dlg, item);
  578.     MySetItemValue(dlg, item, 1);
  579.  
  580. }
  581.  
  582. static void UpdateColumnPopupItems(DialogData* dlg, short item)
  583.     // call this routine if the value of a window popup item has changed
  584.     // it goes through all column popups, making sure that they show the proper colums
  585.  
  586. {    short    i;
  587.     for(i=0; i<maxNrItems; i++)                                // test if there is a column popup that belongs to it
  588.         if (dlg->items[i].type == columnPopupItem)
  589.             if (dlg->items[i].n2 == item)
  590.                 UpdateColumnPopup(dlg, i);
  591. }
  592.  
  593.  
  594. #pragma mark -
  595.  
  596. void SetItemGeneral(DialogData* dlg, short item, void* data)
  597.     // generic routine for setting items. Presently unused
  598. {
  599.     ItemType    type = dlg->items[item].type;
  600.  
  601.     if (type == windowPopupItem)
  602.     {    WindowArray**    array = (WindowArray**)dlg->items[item].data;
  603.         int                i;
  604.         long            newData = *(long*)data;
  605.  
  606.         for (i=0; i<maxNrItemsInWindowPopup; i++)        // find window ref id in list
  607.             if ((**array)[i] == newData)
  608.             {    MySetItemValue(dlg, item, i+1);
  609.                 UpdateColumnPopupItems(dlg, item);        // search for dependent column popup items
  610.                 break;
  611.             }
  612.     }
  613. }
  614.  
  615. void GetItemGeneral(DialogData* dlg, short item, void* data)
  616.     // generic routine getting the setting of items. Presently recognized by
  617.     //    window popup items:    data must be a pointer to a long value, where the window ref ID is returned
  618. {
  619.     ItemType    type = dlg->items[item].type;
  620.  
  621.     if (type == windowPopupItem)
  622.     {    WindowArray**    array = (WindowArray**)dlg->items[item].data;
  623.         if (GetControlMaximum(MyGetItemHandle(dlg, item))==0)            // if menu is empty
  624.             *(long*)data = 0;
  625.         else
  626.             *(long*)data = (**array)[MyGetItemValue(dlg, item)-1];
  627.     }
  628. }
  629.  
  630. #pragma mark -
  631.  
  632. static void DisposeOneItem(DialogData* dlg, short i)
  633.     // disposes any memory allocated for a given item
  634. {
  635.     static const ItemRecord defaultRecord = { unknownItem,0,0,0,nil };
  636.  
  637.     if (dlg->items[i].type == windowPopupItem)
  638.     {    if (dlg->items[i].data != nil)
  639.             DisposeHandle((Handle)dlg->items[i].data);
  640.     }
  641.     dlg->items[i] = defaultRecord;
  642. }
  643.  
  644. void MyAppendDITL(DialogData* dlg, short resID)
  645.     // appens DITL of given res-id to dialog
  646. {
  647.     Handle h = Get1Resource('DITL', resID);
  648.     if (h)
  649.     {    AppendDITL(dlg->dialog, h, overlayDITL);
  650.         ReleaseResource(h);
  651.     }
  652. }
  653.  
  654.  
  655.  
  656. void MyShortenDITL(DialogData* dlg, short nrItems)
  657.     // removes a given number of items from dlg
  658. {
  659.     short    i;
  660.     short    nrItemsNow = CountDITL(dlg->dialog);
  661.     if (nrItems <= 0) return;
  662.  
  663.     for (i=nrItemsNow-nrItems; i<=nrItemsNow; i++)
  664.         DisposeOneItem(dlg, i);
  665.  
  666.     ShortenDITL(dlg->dialog, nrItems);
  667. }
  668.  
  669. #pragma mark -
  670.  
  671. void MyShowDialog(DialogData* dlg)
  672.     // makes the dialog visible
  673. {
  674.     ShowWindow(dlg->dialog);
  675.     SelectWindow(dlg->dialog);                            // make sure it is in front, one never knows when the status window comes up
  676.     InitCursor();
  677. }
  678.  
  679.  
  680. void MyDisposeDialog(DialogData* dlg)
  681.     // call instead of DisposeDialog
  682.     // dlg: the data returned by MyGetNewDialog
  683. {
  684.     int    i;
  685.     if (dlg != nil)
  686.     {
  687.         UnregisterWindow(dlg->dialog);                            // remove dialog from our window list
  688.         if (dlg->dialog) DisposeDialog(dlg->dialog);
  689.  
  690.         for (i=0; i<maxNrItems; i++)
  691.             DisposeOneItem(dlg, i);
  692.  
  693.         DisposePtr((Ptr)dlg);
  694.         ActivateProFitWindows();
  695.     }//if
  696. }
  697.  
  698. static void MakeOKBold(DialogData* dlg)
  699. {
  700.     if (dlg->okItem != 0)                                    // if we should make OK bold
  701.     {
  702.         Rect    r = MyGetItemRect(dlg, dlg->okItem);
  703.         static const RGBColor grayColor = {0x7FFF, 0x7FFF, 0x7FFF};
  704.         PenNormal();
  705.         if (((WindowPeek)dlg->dialog)->hilited == 0)        // if we are not in foreground
  706.             RGBForeColor(&grayColor);
  707.         PenSize(3, 3);
  708.         InsetRect(&r, -4, -4);
  709.         FrameRoundRect(&r, 16, 16);
  710.         PenNormal(); ForeColor(blackColor);
  711.     }
  712. }
  713.  
  714.  
  715. static Boolean MyDialogHandler(long message, void* m, void* param)
  716.     // an event handler for our dialogs
  717. {
  718.     DialogData*    dlg = (DialogData*)param;
  719.     WindowPtr    dialog = dlg->dialog;
  720.     Boolean        retval = false;
  721.     EventRecord*    event = (EventRecord*)m;
  722.     GrafPtr    oldPort;
  723.     GetPort(&oldPort);
  724.     SetPort(dialog);
  725.  
  726.     if (message != 'evnt') return false;            // can only handle event message
  727.  
  728.     if (event->what == updateEvt)
  729.     {
  730.         short    i;
  731.  
  732.         BeginUpdate(dialog);
  733.         PenNormal();
  734.         for (i=0; i<4; i++)
  735.             if (dlg->frames[i].right)
  736.                 FrameRect(&dlg->frames[i]);
  737.         UpdateDialog(dialog, dialog->visRgn);
  738.         MakeOKBold(dlg);
  739.         EndUpdate(dialog);
  740.     }//if updateEvt
  741.     else if (event->what == keyDown)
  742.     {    unsigned char theChar = event->message & charCodeMask;
  743.         if (dlg->cancelItem && CancelEvent(event))                // if cancel
  744.         {    FlashButton(dlg, dlg->cancelItem);
  745.             dlg->itemHit = dlg->cancelItem;
  746.             retval = true;
  747.         }
  748.         else if (dlg->okItem && (theChar==3 || theChar==13))    // if OK
  749.         {    FlashButton(dlg, dlg->okItem);
  750.             dlg->itemHit = dlg->okItem;
  751.             retval = true;
  752.         }
  753.         else retval = DialogSelect(event, &dialog, &dlg->itemHit);
  754.     }
  755.     else if (event->what == activateEvt)
  756.     {    retval = DialogSelect(event, &dialog, &dlg->itemHit);
  757.         MakeOKBold(dlg);                                // frame it in gray or black
  758.     }
  759.     else if (event->what == nullEvent && dlg->timer && dlg->timer < TickCount())
  760.     {    dlg->itemHit = -1;
  761.         dlg->timer = 0;
  762.         retval = true;
  763.     }
  764.     else retval = DialogSelect(event, &dialog, &dlg->itemHit);
  765.  
  766.     SetPort(oldPort);
  767.     return retval;
  768. }
  769.  
  770.  
  771. DialogData* MyGetNewDialog(short resID, short okItem, short cancelItem)
  772.     // call instead of GetNewDialog
  773.     // resID:        the resource ID of the DLOG
  774.     // okItem:        the item to be activated when Enter/Return is pressed (0 if none)
  775.     // cancleItem    the item to be activated when Escape/cmd-. is pressed (0 if none)
  776.     // returns nil if failure
  777. {
  778.     DialogPtr        dialog;
  779.     DialogData*        dlg=nil;
  780.     ModalFilterUPP    stdFilter=nil;
  781.     
  782.     dlg = (DialogData*)NewPtrClear(sizeof(DialogData));
  783.     if (dlg == nil) goto fail;
  784.  
  785.     dialog = GetNewDialog(resID, nil, (WindowPtr)(-1));
  786.     if (dialog == nil) goto fail;
  787.  
  788.     dlg->okItem = okItem;
  789.     dlg->cancelItem = cancelItem;
  790.     dlg->dialog = dialog;
  791.     SetWRefCon(dialog, (long)dlg);
  792.  
  793.     CenterWindow(dialog);
  794.     RegisterWindow(dialog, &MyDialogHandler, dlg);            // register and position it
  795.     DeactivateProFitWindows();                                // this prevents the status window from coming 
  796.  
  797.     return dlg;
  798.  
  799. fail:
  800.     MyDisposeDialog(dlg);
  801.     return nil;
  802. }
  803.  
  804.  
  805.  
  806. void MyModalDialog(DialogData* dlg, short* const itemHit)
  807.     // call instead of ModalDialog
  808.     // dlg: the data returned by MyGetNewDialog
  809.     // Automatically toggles checkboxes when clicked
  810. {
  811.     short        it;
  812.     ItemType    type;
  813.     short        kind;
  814.  
  815.     dlg->itemHit = 0;
  816.  
  817.     do EventLoop(); while (dlg->itemHit == 0);
  818.  
  819.     it = dlg->itemHit;
  820.     type = dlg->items[it].type;
  821.     kind = MyGetItemKind(dlg, it);
  822.  
  823.     if (kind == ctrlItem+chkCtrl)                                // if a checkbox was clicked
  824.         MySetItemValue(dlg, it, !MyGetItemValue(dlg, it));        // then toggle it
  825.     else if (kind == ctrlItem+radCtrl)                            // if a radio
  826.         MySetItemValue(dlg, it, 1);                                // then check it
  827.  
  828.     if (type == windowPopupItem)                                // if a window popup item was clicked
  829.         UpdateColumnPopupItems(dlg, it);                        // then make sure that all its column popups are updated
  830.  
  831.     *itemHit = dlg->itemHit;
  832. }//MyModalDialog
  833.  
  834. #pragma mark -
  835.  
  836. short MyPositionedAlert(short resID, Rect* const position)
  837.     // shows a given alert box, returns the clicked item
  838.     // resID: the res ID of a DLOG
  839.     // position: on entry:    the position of the alert window in global coord. or {0,0,0,0}
  840.     //                        for default position
  841.     //             on exit:    the last position of the alert window
  842. {
  843.     short itemHit;
  844.     DialogData* dlg = MyGetNewDialog(resID, ok, cancel);
  845.     if (dlg==nil) return ok;
  846.     SetGlobalWindowRect(dlg->dialog, position);
  847.     MyShowDialog(dlg);
  848.     MyModalDialog(dlg, &itemHit);
  849.     GetGlobalWindowRect(dlg->dialog, position);
  850.     MyDisposeDialog(dlg);
  851.     return itemHit;
  852. }
  853.  
  854. short MyAlert(short resID)
  855.     // shows a given alert box, returns the clicked item
  856.     // resID: the res ID of a DLOG
  857. {
  858.     Rect    unusedPosition = {0,0,0,0};
  859.     return MyPositionedAlert(resID, &unusedPosition);
  860. }
  861.